package com.ssb.admin.common.utils;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ssb.admin.config.RedisKeys;
import com.ssb.admin.constant.Constants;
import com.ssb.admin.constant.ResponseStatus;
import com.ssb.admin.modules.sys.user.entity.SysUser;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.ServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.util.concurrent.atomic.AtomicInteger;


/**
 * @author duaichao
 * @since 2018/9/7 13:20
 */
@Slf4j
@Component
public class ShiroUtils {

    private static RedisUtils redisUtils;
    private static Boolean redisOpen;

    /**
     * 注入RedisUtil
     * @param isOpen 是否开启Redis
     * @param redisUtils redis工具类
     */
    public ShiroUtils(@Value("${ssadmin.redis.open}") Boolean isOpen, RedisUtils redisUtils){
        ShiroUtils.redisOpen = isOpen;
        ShiroUtils.redisUtils = redisUtils;
    }




    public static String getKaptchaCode(){
        return getCacheValue(RedisKeys.getKaptchaCodeKey(Constants.CAPTCHA_KEY));
    }
    public static void setKaptchaCode( String value){
        //1分钟
        setCacheValue(RedisKeys.getKaptchaCodeKey(Constants.CAPTCHA_KEY),  value, 60);
    }

    /**
     * 锁定账户10分钟
     * @param loginName 登录名
     * @return 是否redis
     */
    public static boolean lockUser(String loginName){
        String key = RedisKeys.getShiroRedisKey(loginName);
        if (redisOpen) {
            // 10分钟过期
            redisUtils.set(key, true, 60*10);
            return true;
        }else{
            return false;
        }
    }
    public static boolean isLockedUser(String loginName){
        if (redisOpen) {
            String key = RedisKeys.getShiroRedisKey(loginName);
            return redisUtils.get(key) != null;
        }else{
            return false;
        }
    }

    /**
     * 读取记录数
     * @param loginName 登录名
     * @return AtomicInteger 计数器
     */
    public static AtomicInteger getPwdRetryCount(String loginName){
        if (redisOpen) {
            return redisUtils.get(loginName,AtomicInteger.class);
        }else{
            return new AtomicInteger(getSessionRetryCount(loginName));
        }
    }

    /**
     * 保存记录数 半个小时内不允许错误次数超过5
     * @param loginName 登录名
     * @param nextCount 最后记录数
     */
    public static void setPwdRetryCount(String loginName, AtomicInteger nextCount){
        setCacheValue(RedisKeys.getShiroRedisKey(loginName), nextCount, 60*30);
    }

    /**
     * 清空记录数
     * @param loginName 登录名
     */
    public static void clearPwdRetryCount(String loginName){
        removeCacheValue(RedisKeys.getShiroRedisKey(loginName));
    }

    /**
     * 保存/读取用户信息
     */
    public static SysUser getUserInfo() {
        String key = RedisKeys.getSessionRedisKey(Constants.SESSION_USER);
        if (redisOpen) {
            return redisUtils.get(key, SysUser.class);
        }else{
            return getSessionValue(key);
        }
    }
    public static void setUserInfo(SysUser sysUser){
        setCacheValue(RedisKeys.getSessionRedisKey(Constants.SESSION_USER),  sysUser, -1);
    }
    public static void removeUserInfo(){
        removeCacheValue(RedisKeys.getSessionRedisKey(Constants.SESSION_USER));
    }

    /**
     * 保存/读取用户权限
     */
    public static Object getAuthorizationInfo(){
        return getCacheValue(RedisKeys.getSessionRedisKey(Constants.SESSION_AUTHORIZATION));
    }
    public static void setAuthorizationInfo(Object authorizationInfo){
        setCacheValue(RedisKeys.getSessionRedisKey(Constants.SESSION_USER), authorizationInfo, -1);
    }
    public static void removeAuthorizationInfo(){
        removeCacheValue(RedisKeys.getSessionRedisKey(Constants.SESSION_AUTHORIZATION));
    }





    private static void removeCacheValue(String key){
        if (redisOpen) {
            redisUtils.delete(key);
        }else{
            removeSessionValue(key);
        }
    }
    private static void setCacheValue(String key, Object value, long time){
        if (redisOpen) {
            // 1分钟过期
            redisUtils.set(key, value, time);
        }else{
            setSessionValue(key, value);
        }
    }
    /**
     * 统一处理逻辑 是否开启redis
     * @param key
     * @param <T>
     * @return T
     */
    private static <T> T getCacheValue(String key){
        //如果开启redis缓存
        if (redisOpen) {
            return (T)redisUtils.get(key);
        }else{
            return (T)getSessionValue(key);
        }
    }
    private static <T> T getSessionValue(String key){
        return (T) SecurityUtils.getSubject().getSession().getAttribute(key);
    }
    private static void setSessionValue(String key, Object value){
        SecurityUtils.getSubject().getSession().setAttribute(key, value);
    }
    private static void removeSessionValue(String key){
        SecurityUtils.getSubject().getSession().removeAttribute(key);
    }
    private static Integer getSessionRetryCount(String loginName){
        Object obj = getSessionValue(getRetryCountSessionKey(loginName));
        if(obj==null){
            return 0;
        }else{
            return Integer.parseInt(obj.toString());
        }
    }


    private static String getRetryCountSessionKey(String loginName){
        return Constants.RETRY_COUNT+"-"+loginName;
    }
    private static String getRetryCountReidsKey(String loginName){
        return RedisKeys.getShiroRedisKey(loginName);
    }


    /**
     * 强制Json返回
     * @param response httpResponse
     * @param res 错误信息
     */

    public static void jsonResponse(ServletResponse response, ResponseStatus res) {
        OutputStream out;
        response.reset();
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        try {
            out = response.getOutputStream();
            ObjectMapper mapper = new ObjectMapper();
            String resJson = mapper.writeValueAsString(R.error(res));
            log.info("###【强制Json返回】："+resJson);
            out.write(resJson.getBytes("UTF-8"));
            out.flush();
            out.close();
        } catch (IOException e) {
            log.error("强制输出json出错");
        }
    }

}
